home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / ms-0.07 / lib / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-27  |  5.8 KB  |  252 lines

  1. /* io.c -- low-level client/server communications and I/O multiplexing */
  2.  
  3. /*  
  4.     This file is part of MandelSpawn, a network Mandelbrot program.
  5.  
  6.     Copyright (C) 1990-1993 Andreas Gustafsson
  7.  
  8.     MandelSpawn is free software; you can redistribute it and/or modify
  9.     it under the terms of the GNU General Public License, version 1,
  10.     as published by the Free Software Foundation.
  11.  
  12.     MandelSpawn is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License,
  18.     version 1, along with this program; if not, write to the Free 
  19.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include "inet.h"
  23. #include "io.h"
  24.  
  25. #include <errno.h>
  26. extern int errno;    /* at least Sony's <errno.h> misses this */
  27.  
  28. struct io_state
  29. { io_transport trans;    /* transport mechanism */
  30.   io_multiplex mux;    /* I/O multiplexing and timeout mechanism */
  31.   int recv_fd;
  32.   int send_fd;
  33.   char *rcvbuf;
  34.   int bufsize;
  35.   char *closure;
  36.   void (*recv_fun)();
  37.   void (*tick_fun)();
  38.   int child_pid;    /* PID of child server, if any */
  39.   int done;
  40.   int ignore_ewouldblock;
  41. };
  42.  
  43.  
  44. /* run the tick function */
  45.  
  46. void io_tick(io)
  47.   io_state *io;
  48. { (*(io->tick_fun))(io->closure);
  49. }
  50.  
  51.  
  52. /* initialize the I/O module */
  53.  
  54. /*
  55.   When a message is received, call recv_fun with the closure,
  56.   message buffer, and message size as arguments.   When a timeout
  57.   occurs, call tick_fun with the closure as the only argument. 
  58. */
  59.  
  60. io_state *
  61. io_init(trans, mux, recv_fd, send_fd, closure, rcvbuf, bufsize,
  62.     recv_fun, tick_fun)
  63.   io_transport trans;    /* transport mechanism */
  64.   io_multiplex mux;    /* I/O multiplexing and timeout mechanism */
  65.   int recv_fd, send_fd;
  66.   char *closure;
  67.   char *rcvbuf;        /* buffer to put received messages in */
  68.   int bufsize;        /* size of the above */
  69.   void (*recv_fun)();    /* function to call on reception of a message */
  70.   void (*tick_fun)();    /* funtion to call on timeout */
  71. { io_state *io = (io_state *) malloc(sizeof(io_state));
  72.   io->trans = trans;
  73.   io->mux = mux;
  74.   io->recv_fd = recv_fd;
  75.   io->send_fd = send_fd;
  76.   io->rcvbuf = rcvbuf;
  77.   io->bufsize = bufsize;
  78.   io->closure = closure;
  79.   io->recv_fun = recv_fun;
  80.   io->tick_fun = tick_fun;
  81.   io->done = 0;
  82.   io->ignore_ewouldblock = 0;
  83.   return(io);
  84. }
  85.  
  86. void io_deinit(io)
  87.   io_state *io; /*ARGSUSED*/
  88. { /* pure laziness */
  89. }
  90.  
  91.  
  92. int io_get_recv_fd(io)
  93.   io_state *io;
  94. {
  95.   return io->recv_fd;
  96. }
  97.  
  98. void io_ignore_ewouldblock(io)
  99.   io_state *io;
  100. {
  101.   io->ignore_ewouldblock = 1;
  102. }
  103.  
  104. int io_send(io, buffer, bufsize, to, tolen)
  105.   io_state *io;
  106.   char *buffer;
  107.   int bufsize;
  108.   char *to;     /* this may be a "struct sockaddr *" or NULL */
  109.   unsigned int tolen;
  110. { int status;
  111.   switch(io->trans)
  112.   {
  113. #ifdef HAVE_SOCKETS
  114.     case IO_TRANS_UDP:
  115.       status = sendto(io->send_fd, buffer, bufsize, 0,
  116.               (struct sockaddr *) to, tolen);
  117.       break;
  118. #endif
  119.     case IO_TRANS_PIPE:
  120.       status = write(io->send_fd, buffer, bufsize);
  121.       break;
  122.     default:
  123.       io_error("transport confusion");
  124.       break;
  125.   }
  126.   return(status);
  127. }
  128.  
  129.   
  130. void io_done(io)
  131.   io_state *io;
  132. { io->done = 1;
  133. }
  134.  
  135.  
  136. #ifdef HAVE_SOCKETS  
  137. void io_handle_socket_input(io)
  138.   io_state *io;
  139. { int fromlen = sizeof(NET_ADDRESS);
  140.   /*
  141.     This previously used read(), but some non-BSD TCP/IP implementations
  142.     don't allow it to be used with connectionless sockets.  Also,
  143.     while the Sun implementation does allow for a null pointer
  144.     for the "from" argument in recvfrom(), the "fromlen" argument 
  145.     may not be a null pointer. 
  146.   */
  147.   if(recvfrom(io->recv_fd, io->rcvbuf, io->bufsize,
  148.           0, (struct sockaddr *) 0, &fromlen) == -1)
  149.  
  150.   {
  151.     if(errno != EWOULDBLOCK || !io->ignore_ewouldblock)
  152.     { perror("read");
  153.       io_error("slave input socket read");
  154.     }
  155.   }
  156.   else
  157.   { (*(io->recv_fun))(io->closure, io->rcvbuf, io->bufsize);
  158.   }
  159. }
  160. #endif /* HAVE_SOCKETS */
  161.  
  162. #ifdef HAVE_SELECT
  163. void io_main_select(io)
  164.   io_state *io;
  165. { fd_set readfds;
  166.   struct timeval tv, zero_tv;
  167.   zero_tv.tv_sec=0;
  168.   zero_tv.tv_usec=0;
  169.   tv.tv_sec=1;
  170.   tv.tv_usec=0;
  171.  
  172.   /* main loop */
  173.   while(! io->done)
  174.   { int nready;
  175.  
  176.     /*
  177.       Keep polling as long as there is data; it's no use bothering 
  178.       with timeouts if we're fully occupied handling incoming data.
  179.     */
  180.     do
  181.     {
  182.     redo_1:
  183.       FD_ZERO(&readfds);
  184.       FD_SET(io->recv_fd, &readfds);
  185.       nready = select(io->recv_fd+1, &readfds, (fd_set *) 0, (fd_set *) 0,
  186.               &zero_tv);
  187.       if(nready == -1)
  188.       { if(errno == EINTR)
  189.       goto redo_1;
  190.     io_error("select");
  191.       }
  192.       else if(nready>0 && FD_ISSET(io->recv_fd, &readfds))
  193.           io_handle_socket_input(io);
  194.     } while(nready);
  195.  
  196.     /*
  197.       No more data; handle any pending timeouts and then go to sleep for
  198.       a second or until new data arrive.
  199.     */
  200.     io_tick(io);
  201.  
  202.   redo_2:
  203.     FD_ZERO(&readfds);
  204.     FD_SET(io->recv_fd, &readfds);
  205.     nready = select(io->recv_fd, &readfds, (fd_set *) 0, (fd_set *) 0,
  206.             &tv);
  207.     if(nready == -1)
  208.     { if(errno == EINTR)
  209.     goto redo_2;
  210.       io_error("select");
  211.     }
  212.     else if(nready>0 && FD_ISSET(io->recv_fd, &readfds))
  213.       io_handle_socket_input(io);
  214.   }
  215. }
  216. #endif /* HAVE_SELECT */
  217.  
  218.  
  219. void io_main_nomux(io)
  220.   io_state *io;
  221. { while(! io->done)
  222.   { read(io->recv_fd, io->rcvbuf, io->bufsize);
  223.     (*(io->recv_fun))(io->closure, io->rcvbuf, io->bufsize);
  224.   }
  225. }
  226.  
  227.  
  228. /*
  229.   The main poll routine.  This is for the non-X version only; in the X
  230.   version, this functionality is supplied by the main event loop. 
  231. */
  232.  
  233. void io_main(io)
  234.   io_state *io;
  235. { switch(io->mux)
  236.   {
  237. #ifdef HAVE_SELECT
  238.     case IO_MUX_SELECT:
  239.       io_main_select(io);
  240.       break;
  241. #endif
  242.     case IO_MUX_NONE:
  243.       io_main_nomux(io);
  244.       break;
  245.     case IO_MUX_XT:
  246.     default:
  247.       io_error("mux confusion");
  248.       break;
  249.   }
  250. }
  251.  
  252.